﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Happy.Query.Filters.Internal
{
    internal class WhereClauseBuilder : FilterVisitor
    {
        private readonly IDictionary<string, object> _arguments;
        private readonly StringBuilder _whereClause = new StringBuilder();
        private readonly List<object> _whereArguments = new List<object>();

        public WhereClauseBuilder(IDictionary<string, object> arguments)
        {
            _arguments = arguments;
        }

        public WhereClause GetWhereClause()
        {
            return new WhereClause(_whereClause.ToString().Trim(), _whereArguments.ToArray());
        }

        public override void Visit(FilterGroup group)
        {
            _whereClause.Append(group.Connector.ToSqlFragment());

            base.Visit(group);

            _whereClause.Append(")");
        }

        public override void Visit(Filter filter)
        {
            _whereClause.Append(filter.Connector.ToSqlFragment());

            var formatArugments = GetFormatArugments(filter);
            _whereClause.AppendFormat(filter.Operator.ToSqlFragmentFormat(), formatArugments.ToArray());

            _whereClause.Append(")");
        }

        private List<object> GetFormatArugments(Filter filter)
        {
            var formatArugments = new List<object> { filter.Property };

            foreach (var operand in filter.Operands)
            {
                switch (operand.OperandType)
                {
                    case OperandType.Constant:
                        formatArugments.Add("@" + _whereArguments.Count);
                        _whereArguments.Add(operand.Value);
                        break;
                    case OperandType.Property:
                        formatArugments.Add(operand.Value.ToString());
                        break;
                    case OperandType.Parameter:
                        formatArugments.Add("@" + _whereArguments.Count);
                        _whereArguments.Add(_arguments[operand.Value.ToString()]);
                        break;
                }
            }

            return formatArugments;
        }
    }
}
